<?php
/**
 * Zeed Platform Project
 * Based on Zeed Framework & Zend Framework.
 *
 * LICENSE
 * http://www.zeed.com.cn/license/
 *
 * @category Zeed
 * @package Zeed_ChangeMe
 * @subpackage ChangeMe
 * @copyright Copyright (c) 2010 Zeed Technologies PRC Inc. (http://www.zeed.com.cn)
 * @author Zeed Team (http://blog.zeed.com.cn)
 * @since 2010-12-6
 * @version SVN: $Id$
 */

class OrderController extends TaskAdminAbstract
{
    private static $_default_status = 0; // 定义默认任务状态为已创建。0：任务已创建；1：已完成；2：任务执行中；3：任务取消；4：失败；

    private static $_default_status_content = 2; // 定义附件表中的文件上传状态。1：表示上传已完成；2：表示正在上传中；

    private static $_finished_status = 1;

    private static $_default_block_size = 4096; // 定义默认单片容量。单位：KB

    /**
     * 预创建上传任务，此时还不知道整个文件的 MD5 值
     */
    public function preCreate()
    {
        $this->addResult(self::RS_SUCCESS, 'json');

        /* 接收参数 */
        $title = $this->input->query('title');
        $filesize = $this->input->query('filesize', 0);
        $folder_id = $this->input->query('folder_id', 0);

        try {
            /* 检查请求方式 */
            if (! $this->input->isAJAX()) {
//                 throw new Zeed_Exception('请求方式错误');
            }

            /* 检查请求参数 */
            if (! $title) {
                throw new Zeed_Exception('参数 title 未提供');
            }
            if (! $filesize) {
                throw new Zeed_Exception('不能上传空文件');
            }

            $timenow = Util_Timer::getMicrotime();

            /* 获取文件 mimetype 信息 */
            $suffix = strrchr($title, '.'); // 获取新文件名后缀，带点
            if ($suffix) {
                $config_filetype = Zeed_Config::loadGroup('filetype');
                $suffix_lower = strtolower($suffix);
                if (! isset($config_filetype[$suffix_lower])) {
                    $suffix_lower = '.*';
                }
                $mimetype = $config_filetype[$suffix_lower]['mimetype'];
                $mediatype = $config_filetype[$suffix_lower]['mediatype'];
            } else {
                $mimetype = '';
                $mediatype = '';
            }

            /* 计算所属目录节点序列 */
            $folder_hid = '0';
            if ($folder_id) {
                $where_folder = array('userid' => $this->_userid, 'fid' => (int) $folder_id);
                $folder_info = Attachment_Model_Folder::instance()->fetchByWhere($where_folder);
                if (empty($folder_info)) {
                    throw new Zeed_Exception('该目录不存在或已删除');
                }
                $folder_hid = $folder_info[0]['hid'];
            }

            /* 计算分片数量 */
            $nums_block = (int) ceil($filesize / 1024 / self::$_default_block_size);

            /* 处理文件标题 */
            $where_same_title = array(
                'folder_hid' => $folder_hid,
                'source_code' => 1,
                'userid' => $this->_userid,
                'status' => 1,
                'title' => $title
            );
            $attachment_same_title = Attachment_Model_Content_Temp::instance()->fetchByWhere($where_same_title);
            if (! empty($attachment_same_title)) {
                $title = Attachment_File::rename($this->_userid, $title, $folder_hid);
            }

            /* 分派任务 */
            $lock_to = $this->_selectWorker();

            /* 组织数据并写入任务表 */
            $set = array(
                'userid' => $this->_userid,
                'title' => $title,
                'title_new' => $title,
                'mimetype' => $mimetype,
                'filesize' => $filesize,
                'hashcode' => '',
                'folder_hid' => $folder_hid,
                'trans_type' => '',
                'nums_block' => $nums_block,
                'lock_to' => $lock_to,
                'is_ru' => 0,
                'ip' => Zeed_Util::clientIP(),
                'ua' => $_SERVER['HTTP_USER_AGENT'],
                'status' => self::$_default_status,
                'ctime' => $timenow,
                'mtime' => $timenow
            );
            $order_id = Task_Model_Order::instance()->addForEntity($set);

            /* 组织数据并写入附件表 */
            $attachment_content = array(
                'pid' => '',
                'userid' => $this->_userid,
                'title' => $title,
                'mediatype' => $mediatype,
                'mimetype' => $mimetype,
                'suffix' => $suffix ? substr($suffix, 1) : 'default',
                'image_width' => 0,
                'image_height' => 0,
                'filepath' => '',
                'filesize' => $filesize,
                'hashcode' => '',
                'folder_hid' => $folder_hid,
                'order_id' => $order_id,
                'source_code' => 1,
                'extra' => '',
                'status' => self::$_default_status_content,
                'ctime' => $timenow,
                'mtime' => $timenow
            );
            if (! $attachment_id = Attachment_Model_Content_Temp::instance()->addForEntity($attachment_content)) {
                throw new Zeed_Exception('文件创建失败，请重试');
            }

            /* 返回数据 */
            $return_data = array('order_id' => $order_id, 'order_status' => 0, 'mediatype' => $mediatype, 'attachment_id' => $attachment_id);
            $this->setData('data', $return_data);
        } catch (Zeed_Exception $e) {
            $this->setStatus($e->getCode() ? $e->getCode() : 1);
            $this->setError('创建任务失败。错误信息：' . $e->getMessage());
        }

        return self::RS_SUCCESS;
    }

    /**
     * 检查是否可以发生秒传
     */
    public function rapidUpload()
    {
        $this->addResult(self::RS_SUCCESS, 'json');

        /* 接收参数 */
        $order_id = $this->input->query('order_id');
        $hashcode = $this->input->query('hashcode');

        try {
            /* 检查请求方式 */
            if (! $this->input->isAJAX()) {
//                 throw new Zeed_Exception('请求方式错误');
            }

            /* 检查请求参数 */
            if (! $order_id) {
                throw new Zeed_Exception('参数 order_id 未提供');
            }
            if (! $hashcode) {
                throw new Zeed_Exception('参数 hashcode 未提供');
            }

            $timenow = Util_Timer::getMicrotime();

            /* 查询任务信息 */
            $order_info = Task_Model_Order::instance()->fetchByPK($order_id);
            if (empty($order_info)) {
                throw new Zeed_Exception('该任务不存在');
            }
            $order_info = $order_info[0];

            /* 若该任务已检查过，则无需重复检查 */
            if ($order_info['hashcode'] == $hashcode) {
                /* 返回数据 */
                $return_data = array('is_ru' => $order_info['is_ru'], 'order_status' => $order_info['status']);
            } else {
                /* 查询文件资源中是否已存在相同文件 */
                $where_exsit = array('hashcode' => $hashcode, 'status' => array('$lt' => 2));
                $attachment_info = Attachment_Model_Content_Temp::instance()->fetchByWhere($where_exsit);

                /* 查询预创建的文件信息 */
                $where_pre = array('order_id' => $order_id);
                $attachment_pre = Attachment_Model_Content_Temp::instance()->fetchByWhere($where_pre);
                if (empty($attachment_pre)) {
                    throw new Zeed_Exception('系统异常，请重试');
                }

                if (empty($attachment_info)) { // 不存在，新上传
                    /* 更新任务信息 */
                    $set_update = array('hashcode' => $hashcode, 'mtime' => $timenow);
                    Task_Model_Order::instance()->updateForEntity($set_update, $order_id);

                    /* 组织新的文件信息 */
                    $set_attachment_new = array(
                        'hashcode' => $hashcode,
                    );

                    /* 更新附件表 */
                    Attachment_Model_Content_Temp::instance()->updateForEntity($set_attachment_new, $attachment_pre[0]['_id']);

                    /* 返回数据 */
                    $return_data = array('is_ru' => 0, 'order_status' => 2);
                } else { // 存在，发生秒传
                    /* 临时处理 - 禁用秒传 @start */
                    return array('is_ru' => 0, 'order_status' => 2);
                    /* 临时处理 - 禁用秒传 @end */

                    /* 组织新的文件信息 */
                    $set_attachment_new = array(
                        'title' => Attachment_File::rename($this->_userid, $order_info['title'], $order_info['folder_hid']),
                        'image_width' => $attachment_info[0]['image_width'],
                        'image_height' => $attachment_info[0]['image_height'],
                        'filepath' => $attachment_info[0]['filepath'],
                        'filesize' => $attachment_info[0]['filesize'],
                        'hashcode' => $attachment_info[0]['hashcode'],
                        'extra' => $attachment_info[0]['extra'],
                        'status' => self::$_finished_status,
                        'mtime' => $timenow
                    );

                    /* 更新附件表 */
                    Attachment_Model_Content_Temp::instance()->updateForEntity($set_attachment_new, $attachment_pre[0]['_id']);

                    /* 更新任务表 */
                    $update_order = array(
                        'filesize' => $attachment_info[0]['filesize'],
                        'hashcode' => $hashcode,
                        'is_ru' => 1,
                        'status' => self::$_finished_status
                    );
                    Task_Model_Order::instance()->updateForEntity($update_order, $order_id);

                    /* 更新文件（夹）同名处理表 */
                    Attachment_Juna::updateCopyNums($this->_userid, $set_attachment_new['title'], 1, $order_info['folder_hid']);

                    /* 返回数据 */
                    $return_data = array('is_ru' => 1, 'order_status' => 1);
                }
            }

            /* 返回数据 */
            $this->setData('data', $return_data);
        } catch (Zeed_Exception $e) {
            $this->setStatus($e->getCode() ? $e->getCode() : 1);
            $this->setError('检查失败。错误信息：' . $e->getMessage());
        }

        return self::RS_SUCCESS;
    }

    /**
     * 取消上传任务，同时删除任务相关的切片，并清除已合片的临时文件 - 支持批量
     * 暂未实现：同时删除任务相关的切片，并清除已合片的临时文件
     */
    public function cancel()
    {
        $this->addResult(self::RS_SUCCESS, 'json');

        /* 接收参数 */
        $order_id = $this->input->query('order_id');

        try {
            /* 检查请求方式 */
            if (! $this->input->isAJAX()) {
//                 throw new Zeed_Exception('请求方式错误');
            }

            /* 检查请求参数 */
            if (! $order_id) {
                throw new Zeed_Exception('参数 order_id 未提供');
            }

            $timenow = Util_Timer::getMicrotime();

            /* 查询上传任务信息 */
            $order_ids = explode(',', $order_id);
            $orders_info = Task_Model_Order::instance()->fetchByPK($order_ids);
            if (! empty($orders_info)) {
                $set_order = array('status' => 3, 'mtime' => $timenow);
                foreach ($orders_info as $k => $v) {
                    /* 判断是否属于自己的任务，若不是，则跳过 */
                    if ($v['userid'] != $this->_userid) {
                        continue;
                    }

                    /* 执行取消 */
                    Task_Model_Order::instance()->updateForEntity($set_order, $v['_id']);
                }
            }
        } catch (Zeed_Exception $e) {
            $this->setStatus($e->getCode() ? $e->getCode() : 1);
            $this->setError('取消任务失败。错误信息：' . $e->getMessage());
        }

        return self::RS_SUCCESS;
    }

    /**
     * 选择将要分配任务的机器
     * 根据未完成的切片数判断，越少的优先选择
     */
    private static function _selectWorker()
    {
        /* 分布式合片机器 IP 集合 */
        $compare_ips = Zeed_Config::loadGroup('urlmapping.ip_compare');

        $nocompare_nums = array();
        foreach ($compare_ips as $k => $v) {
            /* 查询出当前IP下所有未完成任务 */
            $where_order = array('lock_to' => $v, 'status' => array('$in' => array(0, 6)));
            $orders = Task_Model_Order::instance()->fetchByWhere($where_order);

            /* 查询出这些任务下待合成的切片数量 */
            $count_block = 0;
            $order_ids = array();
            if (! empty($orders)) {
                foreach ($orders as $kk => $vv) {
                    $order_ids[] = $vv['_id'];
                }

                $where_block = array('order_id' => array('$in' => $order_ids));
                $count_block = Task_Model_Block_Buffer::instance()->getCount($where_block);
            }

            $nocompare_nums[$v] = $count_block;
        }

        /* 对结果数组的值进行顺序排序 */
        asort($nocompare_nums);

        /* 返回第一个键，即任务量最小的 IP */
        return key($nocompare_nums);
    }
}

// End ^ LF ^ encoding
